package com.leenmvc.core.web.controller;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.leenmvc.core.annotation.ApiDescription;
import com.leenmvc.core.annotation.Note;
import com.leenmvc.core.base.BaseController;
import com.leenmvc.core.base.BaseEntity;
import com.leenmvc.core.base.BaseService;
import com.leenmvc.core.dao.communal.Wrapper;
import com.leenmvc.core.exception.BusinessException;
import com.leenmvc.core.exception.ValidatorException;
import com.leenmvc.core.init.Constant;
import com.leenmvc.core.utils.ConvertUtils;
import com.leenmvc.core.utils.DateUtils;
import com.leenmvc.core.utils.ExcelUtils;
import com.leenmvc.core.utils.TipUtil;
import com.leenmvc.core.utils.collection.MapUtils;
import com.leenmvc.core.utils.http.HttpContextUtils;
import com.leenmvc.core.utils.spring.SpringContextUtils;
import com.leenmvc.core.utils.thread.ThreadLocalManager;
import com.leenmvc.core.utils.validator.ValidatorUtils;
import com.leenmvc.core.base.result.PageData;
import com.leenmvc.core.base.result.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 公共控制器
 * 例如： 角色表 sysRole
 * sys/sysRole/page   获取分页信息  复杂的业务重写 public <T> PageData<T> getPage(Wrapper wrapper)
 * sys/sysRole/sqlPage 获取分页信息（mybatis sql语句） 复杂业务重写 public <T> PageData<T> getPage(String mybatisKey, Map<String, Object> params) {
 * sys/sysRole/getById 根据ID获取角色  复杂业务重写 public <T> T get(Object id)
 * sys/sysRole/getAll  获取全部
 * sys/sysRole/kvs     获取ID,name值对 下拉选通用
 * sys/sysRole/sqlKvs  获取ID，name值对 下拉选通用(由mybatis sql语句提供数据)
 * 如果涉及到复杂的业务 子类中重写 public <T> List<T> listBySqlKey(String id, Object...param)
 * sys/sysRole         POST方法 通用新增    如果涉及到复杂的业务 ，在子类中重写  boolean insert(T t)方法
 * sys/sysRole         PUT方法  通用修改    如果涉及到复杂的业务 ，在子类中重写   boolean update(T t)方法
 * sys/sysRole         DELETE方法 通用删除  如果涉及到复杂的业务 ，在子类中重写   boolean deleteByIds(Long[] ids)方法
 * `
 */
@RestController
@RequestMapping(Constant.COMMON_URL_BASE)
@ApiDescription("基础方法公共控制器")
public class SysCommonRestController extends BaseController {

    private final static Logger logger = LoggerFactory.getLogger(SysCommonRestController.class);

    @GetMapping(Constant.COMMON_URL_PAGE)
    @Note("通过公共方法获取分页记录")
    public Result page(HttpServletRequest request) {
        Class<?>[] cls = getClass(request, 2);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        Map<String, Object> params = HttpContextUtils.getParameterMap(request);
        params.put(Constant.PAGE, MapUtils.getIntValue(params, Constant.PAGE, PageData.DEFAULT_PAGE));
        params.put(Constant.PAGESIZE, MapUtils.getIntValue(params, Constant.PAGESIZE, PageData.DEFAULT_PAGESIZE));
        Wrapper queryWrapper = BaseEntity.getDialect(cls[0]).getWrapperFactory().getQueryWrapper(cls[0], params);
        PageData<Object> data = bean.getPage(queryWrapper);
        return new Result().ok(data);
    }

    @GetMapping(Constant.COMMON_URL_SQL_PAGE)
    @Note("通过公共方法获取分页记录")
    public Result sqlPage(HttpServletRequest request) {
        Class<?>[] cls = getClass(request, 2);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        Map<String, Object> params = HttpContextUtils.getParameterMap(request);
        PageData<Object> data = bean.getPage(MapUtils.getString(params, Constant.SQLKEY, Constant.DEFAULT_GETPAGE_KEY), params);
        return new Result().ok(data);
    }

    @GetMapping(Constant.COMMON_URL_GETBYID)
    @Note("通过公共方法依据ID获取一条记录")
    public Result getById(HttpServletRequest request) {
        Class<?>[] cls = getClass(request, 2);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        Object obj = bean.get(request.getParameter(Constant.PARAM_ID));
        return new Result().ok(obj);
    }

    @GetMapping(Constant.COMMON_URL_GETALL)
    @Note("通过公共方法获取全部记录")
    public Result getAll(HttpServletRequest request) {
        Class<?>[] cls = getClass(request, 2);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        List<Object> list = bean.getAll();
        return new Result().ok(list);
    }

    @GetMapping(Constant.COMMON_URL_GETLIST)
    @Note("通过公共方法获取全部记录")
    public Result getList(HttpServletRequest request) {
        Map<String, Object> params = HttpContextUtils.getParameterMap(request);
        Class<?>[] cls = getClass(request, 2);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        Wrapper queryWrapper = BaseEntity.getDialect(cls[0]).getWrapperFactory().getQueryWrapper(cls[0], params);
        List<Object> list = bean.query(queryWrapper);
        return new Result().ok(list);
    }

    /**
     * 针对复杂的修改业务， 在相应的子类中重写 deleteByIds(Long[] ids) 方法即可
     *
     * @param request
     * @param ids
     * @return
     */
    @DeleteMapping
    @Note("通过公共方法从当前系统删除记录")
    public Result delete(HttpServletRequest request, @RequestBody Long[] ids) {
        ThreadLocalManager.put("requestBody", Arrays.toString(ids));
        Class<?>[] cls = getClass(request, 1);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        int num = bean.deleteByIds(ids);
        if (num <= 0) {
            throw new BusinessException(TipUtil.getTip("DELETE_FAIL", cls[0]));
        }
        return new Result().ok(num);
    }

    /**
     * 查看当前系统中的权限列表（ID， name）
     *
     * @return
     */
    @GetMapping(Constant.COMMON_URL_KVS)
    @Note("通过公共方法获取当前系统的所有角色信息")
    public Result kvs(HttpServletRequest request) {
        Class<?>[] cls = getClass(request, 2);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        Map<String, Object> params = HttpContextUtils.getParameterMap(request);
        Wrapper wrapper = getQueryWrapper(cls[0]);
        wrapper.mapToWrapper(params);
        if(params.get(Constant.PARAMS_WANT) != null) {
            String want = String.valueOf(params.get(Constant.PARAMS_WANT));
            String[] wants = want.split(Constant.COMMA);
            for(int i = 0; i < wants.length; i++) {
                wants[i] = wants[i].trim();
            }
            wrapper.incField(wants);
        } else {
            wrapper.incField(Constant.PARAM_ID, Constant.PARAM_NAME);
        }

        List query = bean.getListMap(wrapper);
        return new Result().ok(query);
    }

    /**
     * 查看当前系统中的权限列表（ID， name）
     *
     * @return
     */
    @GetMapping(Constant.COMMON_URL_SQLKVS)
    @Note("通过公共方法获取id,name的键值对列表信息")
    public Result sqlKvs(HttpServletRequest request) {
        Class<?>[] cls = getClass(request, 2);
        BaseService bean = SpringContextUtils.getBean(cls[1]);
        List query = bean.listBySqlKey(Constant.DEFAULT_KVS_KEY, "language", HttpContextUtils.getLanguage());
        return new Result().ok(query);
    }

    /**
     * 针对复杂的添加业务 在子类中重写 boolean insert(T t)方法
     *
     * @param request
     * @param object
     * @return
     */
    @PostMapping
    @Note("通过公共方法添加记录到当前系统中")
    public Result save(HttpServletRequest request, @RequestBody JSONObject object) {
        try {
            Class<?>[] cls = getClass(request, 1);
            BaseService bean = SpringContextUtils.getBean(cls[1]);
            Object o = JSONObject.parseObject(object.toString(), cls[0]);
            ThreadLocalManager.put(Constant.REQUESTBODY, o);
            if (!bean.insert(o)) {
                throw new BusinessException(TipUtil.getTip("INSERT_FAIL", cls[0]));
            }
            return new Result();
        } catch (JSONException ex) {
            throw new ValidatorException(TipUtil.getTip("REQUESTBODY_COVERT_FAIL"));
        }
    }

    /**
     * 针对复杂的修改业务， 在相应的子类中重写 update(T t) 方法即可
     *
     * @param request
     * @param object
     * @returnThreadHeadFilter.java
     */
    @PutMapping
    @Note("通过公共方法更新记录到当前系统中")
    public Result update(HttpServletRequest request, @RequestBody JSONObject object) {
        try {
            Class<?>[] cls = getClass(request, 1);
            BaseService bean = SpringContextUtils.getBean(cls[1]);
            Object o = JSONObject.parseObject(object.toString(), cls[0]);
            ThreadLocalManager.put(Constant.REQUESTBODY, o);
            if (!bean.update(o)) {
                throw new BusinessException(TipUtil.getTip("UPDATE_FAIL", cls[0]));
            }
            return new Result();
        } catch (JSONException ex) {
            throw new ValidatorException(TipUtil.getTip("REQUESTBODY_COVERT_FAIL"));
        }
    }

    /**
     * 通过公共方法导出Excel
     *
     * @param request
     * @param response
     */
    @GetMapping("export")
    @Note("通过公共方法导出Excel表格")
    public void export(HttpServletRequest request,  HttpServletResponse response) {
        Class<?>[] cls = getClass(request, 2);
        Map<String, Object> params = HttpContextUtils.getParameterMap(request);
        params.remove("token");
        String fileName = DateUtils.format(new Date(), "yyyy-MM-dd-HH-mm-ss");
        Wrapper queryWrapper = BaseEntity.getDialect(cls[0]).getWrapperFactory().getQueryWrapper(cls[0], params);
        List<Object> logs = query(queryWrapper);
        Class<?> excelEntity = BaseEntity.getExcelEntity(cls[0]);
        List excels = ConvertUtils.sourceToTarget(logs, excelEntity);
        try {
            ExcelUtils.exportExcel(response, fileName, excels, excelEntity);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 根据url获取 Class
     *
     * @param request
     * @return
     */
    private Class<?>[] getClass(HttpServletRequest request, int index) {
        Object url = request.getParameter("url");
        ValidatorUtils.notNull(TipUtil.getTip("COMMON_NO_URL"), url);
        String[] urlArr = url.toString().split("/");
        return BaseEntity.entityMap.get(urlArr[urlArr.length - index]).getCorrespondingClss();
    }

}
